#include "devinsight.h"


PG_MODULE_MAGIC;


/*
 * 总得有个主页吧。 也可在重启后触发内核加载.so
 */
DVI_DEF_SQL_FUNCTION(devinsight, "说明书函数。也可用于在数据库重启后触发加载.so")
Datum devinsight(PG_FUNCTION_ARGS)
{
    static DviFunctionDesc func_descs[] = {
        #include "dev_func_desc.txt"
    };

    const int res_column_count = 3;
    FuncCallContext* funcctx = NULL;
    if (SRF_IS_FIRSTCALL()) {
        funcctx = SRF_FIRSTCALL_INIT();
        funcctx->max_calls = sizeof(func_descs) / sizeof(DviFunctionDesc);

        MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
        TupleDesc tupledesc = CreateTemplateTupleDesc(res_column_count, false);
        TupleDescInitEntry(tupledesc, (AttrNumber)1, "type", CSTRINGOID, -1, 0);
        TupleDescInitEntry(tupledesc, (AttrNumber)2, "name", CSTRINGOID, -1, 0);
        TupleDescInitEntry(tupledesc, (AttrNumber)3, "description", CSTRINGOID, -1, 0);
        funcctx->tuple_desc = BlessTupleDesc(tupledesc);
        MemoryContextSwitchTo(oldcontext);
    }

    funcctx = SRF_PERCALL_SETUP();
    uint32 idx = funcctx->call_cntr;
    if (idx < funcctx->max_calls) {
        DviFunctionDesc* func = &func_descs[idx];
        Datum values[res_column_count] = {PointerGetDatum(func->type), PointerGetDatum(func->name), PointerGetDatum(func->desc)};
        bool nulls[res_column_count] = {0, 0, 0};
        HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
        SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
    } else {
        SRF_RETURN_DONE(funcctx);
    }
}


/*
 * 获取t_thrd与u_sess。
 * 防止有些情况下报错 Cannot find thread-loacl var ...
 */
const knl_thrd_context* dviThrd()
{
    return &t_thrd;
}
const knl_session_context* dviUsess()
{
    return u_sess;
}




// DVI_DEF_SQL_FUNCTION(dvi_semop, "同步信号。示例: 1、设置N个信号 dvi_semop('add', N), 2、消耗N个信号 dvi_semop('wait', N)")
/*
Datum dvi_semop(PG_FUNCTION_ARGS)
{

    static 

    char* action = TextDatumGetCString(PG_GETARG_TEXT_P(0));
    int num = PG_GETARG_INT32(1);

    if (strcasecmp(action, 'wait') == 0) {
    
    }
}
*/



DVI_DEF_SQL_FUNCTION(dvi_syncflag, "同步信号。示例: 1、设置信号值N dvi_sycnflag('set', N), 2、消耗等待信号N后清零信号值 dvi_sycnflag('wait', N), 3、重置信号值为0 'reset', 4、中断信号值为-1 dvi_sycnflag('abort')，5、查看信号值")
Datum dvi_syncflag(PG_FUNCTION_ARGS)
{
    static pg_atomic_uint32 flag;

    char* action = TextDatumGetCString(PG_GETARG_TEXT_P(0));
    uint32 value = (uint32)PG_GETARG_INT32(1);

    uint32 from_value = 0;
    uint32 change_to_value = 0;

    if (strcasecmp(action, "set") == 0) {
        from_value = 0;
	change_to_value = value;

    } else if (strcasecmp(action, "wait") == 0) {
        from_value = value;
	change_to_value = 0;

    } else if (strcasecmp(action, "reset") == 0) {
        pg_atomic_write_u32(&flag, (uint32)0);
        PG_RETURN_BOOL(true);

    } else if (strcasecmp(action, "abort") == 0) {
	pg_atomic_write_u32(&flag, (uint32)-1);
        PG_RETURN_BOOL(true);

    } else if (strcasecmp(action, "show") == 0) {
	from_value = pg_atomic_read_u32(&flag);
        ereport(NOTICE, (errmsg("devinsight syncflag value is %u", from_value)));
	PG_RETURN_BOOL(true);
    
    } else {
        ereport(ERROR, (errmsg("unknown param")));
    }
	
	   
    uint32 oldvalue = 0;
    do {
	pg_usleep(100L);

        if (oldvalue == (uint32)-1) {
	    PG_RETURN_BOOL(false);
	}

	oldvalue = from_value;
    } while (!pg_atomic_compare_exchange_u32(&flag, &oldvalue, change_to_value));

    PG_RETURN_BOOL(true);

}


